package com.xinlan.imageeditlibrary.editimage.utils;


import android.content.Context;
import android.content.res.Resources;
import android.graphics.*;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.ExifInterface;
import android.net.Uri;
import android.util.Base64;
import android.util.Log;

import java.io.*;
import java.util.Arrays;

public class BitmapUtil {

    public static final String TAG = "BitmapUtil";

    /**
     * 释放bitmap
     *
     * @param bmp 需要释放的bitmap
     */
    public static void release(Bitmap bmp) {
        if (bmp != null && !bmp.isRecycled()) {
            bmp.recycle();
            bmp = null;
        }
    }

    /**
     * bitmap 是否有效
     *
     * @param bmp 需要检查有效性的bitmap
     * @return
     */
    public static boolean isAvailableBitmap(Bitmap bmp) {
        if (bmp != null && !bmp.isRecycled()) {
            return true;
        }

        return false;
    }

    /**
     * 获取bitmap的字节大小
     *
     * @param bitmap
     * @return bitmap字节数
     */
    public static int getBitmapSize(Bitmap bitmap) {
        return bitmap.getRowBytes() * bitmap.getHeight();
    }

    /**
     * 获取对应路径图片的Orientation
     *
     * @param pPath
     * @return exif值
     */
    public static int getBitmapOrientation(String pPath) {
        ExifInterface exif = null;
        int lRes = 1;
        try {
            exif = new ExifInterface(pPath);
            lRes = Integer.parseInt(exif.getAttribute(ExifInterface.TAG_ORIENTATION));
            lRes = lRes == 0 ? 1 : lRes;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return lRes;
    }

    /**
     * 拿到宽高比
     *
     * @param filePath
     * @return失败则返回0 s
     */
    public static float getAspectRatio(String filePath) {
        float aspectRatio = 0;
        // bitmap option
        BitmapFactory.Options options = new BitmapFactory.Options();
        /** 不真正的进行读 **/
        options.inJustDecodeBounds = true;
        // pre read the bitmap,the result is null
        Bitmap bmp = BitmapFactory.decodeFile(filePath, options);
        // the real size of the bitmap
        if (options != null) {
            int realWidth = options.outWidth;
            int realHeight = options.outHeight;
            if (realHeight > 0) {
                aspectRatio = (float) realWidth / (float) realHeight;
            }
        }
        return aspectRatio;
    }

    /**
     * 读取图片的宽高
     * 读取不到图片等情况默认返回 -1
     *
     * @param filePath
     * @return 返回长度为2的数组 index = 0时，值为宽，index = 1时，值为高
     */
    public static int[] getBitmapWidthAndHeightByPath(String filePath) {

        int[] wh = new int[2];
        Arrays.fill(wh, -1);

        if (filePath == null) {
            return wh;
        }

        // bitmap option
        BitmapFactory.Options options = new BitmapFactory.Options();
        /** 不真正的进行读 **/
        options.inJustDecodeBounds = true;
        // pre read the bitmap,the result is null
        Bitmap bmp = BitmapFactory.decodeFile(filePath, options);
        // the real size of the bitmap
        if (options != null) {
            wh[0] = options.outWidth;
            wh[1] = options.outHeight;
        }
        return wh;
    }
    
    /**
     * 获取适应指定宽高的bitmap
     *
     * @param pBitmap       源bitmap
     * @param screenWidth   指定的宽度
     * @param screenHeight  指定的高度
     * @param isFitXY       是否覆盖屏幕，true :最小边适应，即生成的bitmap某一边和指定的宽高相等，一边则小于指定的宽高
     *                      false:最大边适应，即生成的bitmap全屏展示，生成的bitmap某一边和指定的宽高相等，一边则大于指定的宽高
     * @param isNeedRelease
     * @return
     */
    public static Bitmap getFittingScreenBitmap(Bitmap pBitmap, float screenWidth, float screenHeight, boolean isFitXY, boolean isNeedRelease) {

        if (!BitmapUtil.isAvailableBitmap(pBitmap)) {
            return null;
        }

        Bitmap bmpResult = null;
        float bmpWidth = pBitmap.getWidth();
        float bmpHeight = pBitmap.getHeight();

        try {
            float scale = MathUtils.getScaleValueFittingScreen(screenWidth, screenHeight, bmpWidth, bmpHeight, isFitXY);

            if (scale == 1) { // 返回原图
                bmpResult = pBitmap.copy(Bitmap.Config.ARGB_8888, true);
            } else {
                bmpResult = Bitmap.createScaledBitmap(pBitmap, (int) Math.ceil(scale * bmpWidth), (int) Math.ceil(scale * bmpHeight), true);
            }

        } catch (OutOfMemoryError e) {
        }

        if (isNeedRelease) {
            BitmapUtil.release(pBitmap);
        }

        return bmpResult;
    }

    /**
     * 加载图片
     *
     * @param filePath 文件路径
     * @return bitmap
     */
    public static Bitmap loadBitmapFromSDcard(String filePath) {
        return loadBitmapFromSDcard(filePath, -1, -1, -1);
    }

    /**
     * 加载图片
     *
     * @param filePath  加载图片
     * @param maxWidth  最大宽度
     * @param maxHeight 最大高度
     * @return bitmap
     */
    public static Bitmap loadBitmapFromSDcard(String filePath, int maxWidth, int maxHeight) {
        return loadBitmapFromSDcard(filePath, -1, maxWidth * maxHeight, -1);
    }

    /**
     * 加载图片
     *
     * @param filePath       文件路径
     * @param minSideLength  默认-1，最大像素值匹配生成的scale值需为偶数，如果通过计算得到
     *                       的scale值为3，当minSideLength = -1，时，scale取下限2，反之取4
     * @param maxNumOfPixels 最大像素值，即为想要生成的bitmap的最大宽高乘积
     * @param pSampleSize    图片的scale值，可以传入自己需要的scale大小，当pSampleSize > 0时，
     *                       前面设置的参数无效，直接根据pSampleSize来压缩图片
     * @return bitmap
     */
    public static Bitmap loadBitmapFromSDcard(String filePath, int minSideLength, int maxNumOfPixels
            , int pSampleSize) throws OutOfMemoryError{
        FileInputStream input = null;
        // bitmap option
        BitmapFactory.Options options = new BitmapFactory.Options();

        /** 不真正的进行读 **/
        options.inJustDecodeBounds = true;

        // pre read the bitmap,the result is null
        Bitmap lResBitmap = BitmapFactory.decodeFile(filePath, options);

        // the real size of the bitmap
        int realWidth = options.outWidth;
        int realHeight = options.outHeight;

        /** 预期大小 **/
        int resultWidth = realWidth;
        int resultHeight = realHeight;

        if (pSampleSize > 0) {
            options.inSampleSize = pSampleSize;
        } else {
            options.inSampleSize = computeSampleSize(options, minSideLength, maxNumOfPixels);
        }

        // read real data
        options.inJustDecodeBounds = false;
        options.inPurgeable = true;
        options.inInputShareable = true;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        Bitmap lTmpBitmap = null;
        try {
            lTmpBitmap = BitmapFactory.decodeFile(filePath, options);
        } catch (Exception e) {
            return null;
        }

        int lOrientation = BitmapUtil.getBitmapOrientation(filePath);

        if (lOrientation != 1) {
            lResBitmap = getBitmapByOrientation(lTmpBitmap, lOrientation, true);
        } else {
            lResBitmap = lTmpBitmap;
        }
        return lResBitmap;
    }

    /**
     * 根据exif的 orientation值来处理bitmap
     *
     * @param sourceBitmap  源bitmap
     * @param orientation   exif的 orientation，对应 0 - 8
     * @param isNeedRelease 是否需要释放源bitmap
     * @return bitmap
     */
    public static Bitmap getBitmapByOrientation(Bitmap sourceBitmap, int orientation, boolean isNeedRelease) {

        Bitmap lResBitmap = null;

        if (orientation != 1) {
            Matrix matrix = new Matrix();
            switch (orientation) {
                case 1:
                    break;
                case 2:
                    matrix.preScale(-1, 1);
                    break;
                case 3:
                    matrix.preRotate(180);
                    break;
                case 4:
                    matrix.preScale(1, -1);
                    break;
                case 5:
                    matrix.preRotate(90);
                    matrix.preScale(-1, 1);
                    break;
                case 6:
                    matrix.preRotate(90);
                    break;
                case 7:
                    matrix.preScale(-1, 1);
                    matrix.preRotate(90);
                    break;
                case 8:
                    matrix.preRotate(270);
                    break;
                default:
                    break;
            }

            if (matrix.isIdentity()) {
                lResBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight(),
                        null, false);
            } else {
                lResBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight(),
                        matrix, true);
            }

            if (isNeedRelease && lResBitmap != sourceBitmap) {
                sourceBitmap.recycle();
            }
        }

        return lResBitmap;
    }


    /***
     *  从stream中加载图片
     * @param stream
     * @param maxW
     * @param maxH
     * @return
     */
    public static Bitmap loadBitmapFromStream(final InputStream stream, final int maxW, final int maxH) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        Bitmap bitmap = null;
        options.inScaled = false;
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        options.inJustDecodeBounds = true;
        Rect rect = new Rect();
        BitmapFactory.decodeStream(stream,rect,options);
        options.inSampleSize = computeSampleSize(options, -1, maxW * maxH);
        Log.e(TAG, "options.inSampleSize = " + options.inSampleSize);
        options.inJustDecodeBounds = false;
        options.inPurgeable = true;
        bitmap = BitmapFactory.decodeStream(stream,rect,options);
        return bitmap;
    }



    /**
     * 加载图片
     *
     * @param byteData 源数据
     * @param maxW     最大宽度
     * @param maxH     最大高度
     * @return bitmap
     * @throws IOException
     */
    public static Bitmap loadBitmapFromByte(final byte[] byteData, int maxW, int maxH) throws IOException {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        Bitmap bitmap = null;
        options.inScaled = false;
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        options.inJustDecodeBounds = true;

        BitmapFactory.decodeByteArray(byteData, 0, byteData.length, options);
        double w = options.outWidth;
        double h = options.outHeight;
        options.inSampleSize = computeSampleSize(options, -1, maxW * maxH);
        Log.e(TAG, "options.inSampleSize = " + options.inSampleSize);
        options.inJustDecodeBounds = false;
        options.inPurgeable = true;
        bitmap = BitmapFactory.decodeByteArray(byteData, 0, byteData.length, options);
        return bitmap;
    }

    /**
     * save a Bitmap to the object SD filePath
     *
     * @param savePath 图片保存路径
     * @param bmp      需要保存的bitmap
     * @return
     */
    public static boolean saveBitmapToSDcard(String savePath, Bitmap bmp, Bitmap.CompressFormat format) {

        File f = new File(savePath);
        try {
            f.createNewFile();
        } catch (IOException e) {
            Log.i(TAG, "file create failed");
            return false;
        }
        FileOutputStream fOut = null;
        try {
            fOut = new FileOutputStream(f);
        } catch (FileNotFoundException e) {
            Log.i(TAG, "file create failed");
            return false;
        }
        bmp.compress(format, 100, fOut);
        try {
            fOut.flush();
            fOut.close();
        } catch (IOException e) {
            Log.i(TAG, "save failed by ioexception");
            return false;
        }
        return true;

    }

    /**
     * 圆角裁剪
     *
     * @param bitmap        源bitmap
     * @param pixels        圆角的像素值
     * @param isNeedRelease 是否需要释放源bitmap
     * @return
     */
    public static Bitmap toRoundCorner(Bitmap bitmap, int pixels, boolean isNeedRelease) {

        Bitmap output = null;
        try {
            output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(output);

            final int color = 0xff424242;
            final Paint paint = new Paint();
            final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            final RectF rectF = new RectF(rect);
            final float roundPx = pixels;

            paint.setAntiAlias(true);
            canvas.drawARGB(0, 0, 0, 0);
            paint.setColor(color);
            canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            canvas.drawBitmap(bitmap, rect, rect, paint);
            if (isNeedRelease) {
                BitmapUtil.release(bitmap);
            }
        } catch (Exception e) {
            Log.e(TAG, "内存溢出，发生OOM了");
        }

        return output;
    }

    /**
     * 按指定的scale缩放bitmap
     *
     * @param bitmap
     * @param scale
     * @param recycle
     * @return
     */
    public static Bitmap resizeBitmapByScale(
            Bitmap srcBitmap, float scale, boolean isNeedReleaseSrcBitmap) {
        if (!isAvailableBitmap(srcBitmap)) {
            return null;
        }
        int width = Math.round(srcBitmap.getWidth() * scale);
        int height = Math.round(srcBitmap.getHeight() * scale);
        if (width == srcBitmap.getWidth()
                && height == srcBitmap.getHeight()) {
            return srcBitmap;
        }
        Bitmap target = null;
        try {
            target = Bitmap.createBitmap(width, height, getConfig(srcBitmap));
            Canvas canvas = new Canvas(target);
            canvas.scale(scale, scale);
            Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
            canvas.drawBitmap(srcBitmap, 0, 0, paint);
            if (isNeedReleaseSrcBitmap) {
                release(srcBitmap);
            }
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
        }
        return target;
    }

    /**
     * 获取图片的config，默认为Bitmap.Config.ARGB_8888
     *
     * @param bitmap
     * @return
     */
    private static Bitmap.Config getConfig(Bitmap bitmap) {
        Bitmap.Config config = bitmap.getConfig();
        if (config == null) {
            config = Bitmap.Config.ARGB_8888;
        }
        return config;
    }

    /**
     * 按图片的宽高较小值来居中裁剪bitmap
     *
     * @param bitmap  源bitmap
     * @param recycle 是否需要释放源bitmap
     * @return
     */
    public static Bitmap cropCenter(Bitmap bitmap, boolean recycle) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        if (width == height) return bitmap;
        int size = Math.min(width, height);

        Bitmap target = Bitmap.createBitmap(size, size, getConfig(bitmap));
        Canvas canvas = new Canvas(target);
        canvas.translate((size - width) / 2, (size - height) / 2);
        Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);
        canvas.drawBitmap(bitmap, 0, 0, paint);
        if (recycle) bitmap.recycle();
        return target;
    }

    /**
     * 裁剪图片
     *
     * @param source 源bitmap
     * @param x      起点x坐标
     * @param y      起点y坐标
     * @param width  要裁剪的宽度
     * @param height 要裁剪的高度
     * @return
     */
    private static Bitmap cropBitmap(
            Bitmap source, int x, int y, int width, int height) {
        // Re-implement Bitmap createBitmap() to always return a mutable bitmap.
        Canvas canvas = new Canvas();

        Bitmap bitmap;
        Paint paint;
        paint = new Paint(Paint.FILTER_BITMAP_FLAG);
        paint.setAntiAlias(true);
        bitmap = Bitmap.createBitmap(width, height, getConfig(source));
        bitmap.setDensity(source.getDensity());
        canvas.setBitmap(bitmap);

        Rect srcBounds = new Rect(x, y, x + width, y + height);
        RectF dstBounds = new RectF(0, 0, width, height);
        canvas.drawBitmap(source, srcBounds, dstBounds, paint);
        return bitmap;
    }


    /**
     * compute Sample Size
     *
     * @param options
     * @param minSideLength
     * @param maxNumOfPixels
     * @return
     */
    public static int computeSampleSize(BitmapFactory.Options options,
                                        int minSideLength, int maxNumOfPixels) {
        int initialSize = computeInitialSampleSize(options, minSideLength,
                maxNumOfPixels);

        int roundedSize;
        if (initialSize <= 8) {
            roundedSize = 1;
            while (roundedSize < initialSize) {
                roundedSize <<= 1;
            }
        } else {
            roundedSize = (initialSize + 7) / 8 * 8;
        }

        return roundedSize;
    }

    /**
     * compute Initial Sample Size
     *
     * @param options
     * @param minSideLength
     * @param maxNumOfPixels
     * @return
     */
    private static int computeInitialSampleSize(BitmapFactory.Options options,
                                                int minSideLength, int maxNumOfPixels) {
        double w = options.outWidth;
        double h = options.outHeight;

        // 上下限范围
        int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math
                .sqrt(w * h / maxNumOfPixels));
        int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(
                Math.floor(w / minSideLength), Math.floor(h / minSideLength));

        if (upperBound < lowerBound) {
            // return the larger one when there is no overlapping zone.
            return lowerBound;
        }

        if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
            return 1;
        } else if (minSideLength == -1) {
            return lowerBound;
        } else {
            return upperBound;
        }
    }

    /**
     * bitmap转drawable
     *
     * @param res
     * @param bitmap
     * @return
     */
    public static Drawable bitmap2Drawable(Resources res, Bitmap bitmap) {
        return new BitmapDrawable(res, bitmap);
    }

    /**
     * drawable 转 bitmap
     *
     * @param drawable
     * @return
     */
    public static Bitmap drawable2Bitmap(Drawable drawable) {
        Bitmap bitmap = Bitmap.createBitmap(

                drawable.getIntrinsicWidth(),

                drawable.getIntrinsicHeight(),

                drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888

                        : Bitmap.Config.RGB_565);

        Canvas canvas = new Canvas(bitmap);

        drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());

        drawable.draw(canvas);

        return bitmap;
    }

    /**
     * 保存bitmap到指定路径
     *
     * @param bmp
     * @param filePath
     * @param format
     */
    public static boolean saveBitmap2SD(final Bitmap bmp, final String filePath, final Bitmap.CompressFormat format) {
        File file = new File(filePath);
        try {
            file.createNewFile();
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
            return false;
        }
        FileOutputStream fOut = null;
        try {
            fOut = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            Log.e(TAG, e.getMessage());
            return false;
        }
        bmp.compress(format, 100, fOut);
        try {
            fOut.flush();
            fOut.close();
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
            return false;
        }
        return true;
    }
    
    /**
	 * bitmap转为base64
	 * 
	 * @param bitmap
	 * @return
	 */
	public static String bitmapToBase64(Bitmap bitmap) {
		String result = null;
		ByteArrayOutputStream baos = null;
		try {
			if (bitmap != null) {
				baos = new ByteArrayOutputStream();
				bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
				baos.flush();
				baos.close();
				byte[] bitmapBytes = baos.toByteArray();
				result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (baos != null) {
					baos.flush();
					baos.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return result;
	}
}
